﻿using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.GridFS;
using Newtonsoft.Json;
using Ongoal.Quotation.Service;
using Ongoal.Quotation.Service.Interface;
using Ongoal.Quotation.Service.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ongoal.Quotation.Service
{
    /// <summary>
    /// 
    /// </summary>
    public class MongoFileRepo : ServiceBase, IMongoFileRepo
    {
        public IMongoClient _client;
        private IMongoDatabase _db;
        private Dictionary<string, IGridFSBucket> bucketDic = new Dictionary<string, IGridFSBucket>();
        private List<MongoSetting> mongodbList;


        private void Init()
        {
            if (mongodbList == null || mongodbList.Count == 0)
            {
                var dbcfgstr = this.Config!["MongoDB"];
                if (!string.IsNullOrEmpty(dbcfgstr))
                    mongodbList = JsonConvert.DeserializeObject<List<MongoSetting>>(dbcfgstr);
                else
                    mongodbList = this.Config!.GetSection("MongoDB").Get<List<MongoSetting>>();

                foreach (var item in mongodbList)
                {
                    _client = new MongoClient(item.ConnectionStr);
                    _db = _client.GetDatabase(item.DBName);
                    bucketDic.Add(item.DBName, new GridFSBucket(_db));
                }
            }
        }
        public ObjectId GetInternalId(string id)
        {
            if (!ObjectId.TryParse(id, out ObjectId internalId))
                internalId = ObjectId.Empty;

            return internalId;
        }

        /// <summary>
        /// 指定库下载文件
        /// </summary>
        /// <param name="id"></param>
        /// <param name="bucketName"></param>
        /// <returns></returns>
        public async Task<GridFSFileInfo> GetFileById(string id, string bucketName = "")
        {
            Init();
            var filter = Builders<GridFSFileInfo>.Filter.Eq("_id", GetInternalId(id));
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            return await bucket.Find(filter).FirstOrDefaultAsync();
        }

        public async Task<GridFSFileInfo> GetFileById(ObjectId id, string bucketName = "")
        {
            Init();
            var filter = Builders<GridFSFileInfo>.Filter.Eq("_id", id);
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            return await bucket.Find(filter).FirstOrDefaultAsync();
        }
        public async Task<GridFSFileInfo> FindFileByFileName(string filename)
        {
            Init();
            var filter = Builders<GridFSFileInfo>.Filter.Eq("filename", filename);
            var bucket = bucketDic.Values.First();
            return await bucket.Find(filter).FirstOrDefaultAsync();
        }
        public async Task<ObjectId> UploadFile(string fileName, Stream source, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            var id = await bucket.UploadFromStreamAsync(fileName, source);
            return id;
        }

        public async Task<GridFSDownloadStream<ObjectId>> DownloadFileStreamSeekable(string id, string bucketName = "")
        {
            Init();
            var options = new GridFSDownloadOptions
            {
                Seekable = true
            };
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            return await bucket.OpenDownloadStreamAsync(GetInternalId(id), options);
        }

        public async Task<GridFSDownloadStream<ObjectId>> DownloadFileStreamSeekable(ObjectId id, string bucketName = "")
        {
            Init();
            var options = new GridFSDownloadOptions
            {
                Seekable = true
            };
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            return await bucket.OpenDownloadStreamAsync(id, options);
        }

        public async Task<GridFSDownloadStream<ObjectId>> DownloadFileStream(string id, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            return await bucket.OpenDownloadStreamAsync(GetInternalId(id));
        }

        public async Task<GridFSDownloadStream<ObjectId>> DownloadFileStream(ObjectId id, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            return await bucket.OpenDownloadStreamAsync(id);
        }
        public void DownloadToStream(ObjectId id, FileStream outfile, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            bucket.DownloadToStream(id, outfile);
        }

        public async Task DeleteFile(string id, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            await bucket.DeleteAsync(GetInternalId(id));
        }

        public async Task DeleteFile(ObjectId id, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            await bucket.DeleteAsync(id);
        }

        public async Task RenameFile(string id, string newFilename, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            await bucket.RenameAsync(GetInternalId(id), newFilename);
        }

        public async Task RenameFile(ObjectId id, string newFilename, string bucketName = "")
        {
            Init();
            IGridFSBucket bucket;
            if (!string.IsNullOrEmpty(bucketName) && bucketDic.Keys.Contains(bucketName))
            {
                bucket = bucketDic[bucketName];
            }
            else
            {
                bucket = bucketDic.Values.First();
            }
            await bucket.RenameAsync(id, newFilename);
        }

        /// <summary>
        /// 查询多个文件信息
        /// </summary>
        /// <returns></returns>
        public async Task DeleteMongoFile()
        {
            Init();
            var filter = Builders<GridFSFileInfo>.Filter;
            //var filter1 = filter.Lte("uploadDate", "2024-02-22");
            //var filter2 = filter.Regex("filename", "/ongalmes.sql/");
            var Date = DateTime.Now.AddDays(-10);
            //var Date = "2024-02-01";
            FilterDefinition<GridFSFileInfo> filter3 = string.Format("{{filename: /.sql/,uploadDate:{{$lte: new Date('{0}')}}}}", Date);
            var bucket = bucketDic.Values.First();
            var List = await bucket.Find(filter3).ToListAsync();
            if (List != null && List.Count() > 0)
            {
                foreach (var item in List)
                {
                    bucket.Delete(item.Id);
                }
            }
        }
    }
}
